﻿using System;
using System.ComponentModel;
using System.Reflection;
using System.Runtime.Serialization;

using GameLibrary.Internal;

namespace G.Model
{
    [DataContract]
    public class GameSpaceDef : 
        HasName, HasXml,
        INotifyPropertyChanged
    {
        public delegate void SizeChangedHandler(GameSpaceDef pGameDef);
            
        public event PropertyChangedEventHandler PropertyChanged;
        public event EventHandler DirtyChanged;
        public event SizeChangedHandler SizeChangedEvent;
        
        [DataMember(Name="GameElementDefs")]
        private readonly GameElementDefs _GameElementDefs;
        
        [DataMember(Name="GamePlayerDefs")]
        private readonly GamePlayerDefs _GamePlayerDefs;
        
        [DataMember(Name="GameGlobalDef")]
        private readonly GameGlobalDef _GameGlobalDef;
        
        [DataMember(Name="GameTaskDefs")]
        private readonly GameTaskDefs _GameTaskDefs;
        
        [DataMember(Name="Width")]
        private int _Width;
        
        [DataMember(Name="Height")]
        private int _Height;
        
        private string _Name = "Game";
        private bool _IsDirty;

        public GameSpaceDef()
        {
            _Height = 5;
            _Width = 5;
            _GameElementDefs = new GameElementDefs(this);
            _GamePlayerDefs = new GamePlayerDefs(this);
            _GameTaskDefs = new GameTaskDefs(this);
            _GameGlobalDef = new GameGlobalDef(this);
            _GamePlayerDefs.DeterminePlayers(this);
        }
        
        public static GameSpaceDef Load(Assembly assembly, string path)
        {
            return SpaceSerializer.toObjectManifestResource(assembly, path);
        }
        
        public static GameSpaceDef Load(string xml)
        {
            return SpaceSerializer.toObject(xml);
        }
        
        private void FireDirtyFlagChanged()
        {
            if (DirtyChanged != null) {
                DirtyChanged(this, new EventArgs());
            }
        }
        
        internal void PostInit()
        {
            foreach (GameElementDef element in _GameElementDefs) {
                element.GameDef = this;
            }
            
            foreach (GamePlayerDef player in _GamePlayerDefs) {
                player.GameDef = this;
            }
            
            foreach (GameTaskDef task in _GameTaskDefs) {
                task.GameDef = this;
            }
            
            _GameTaskDefs.GameDef = this;
            _GameElementDefs.GameDef = this;
            _GameGlobalDef.GamePlayerValueDefs.GameDef = this;
            _GameGlobalDef.GameValueDefs.GameDef = this;
            _GameGlobalDef.GameDef = this;
        }

        [IgnoreDataMember]
        public int Width
        {
            get { return _Width; }
            set
            {
                if (_Width != value)
                {
                    _Width = value;
                    FireSizeChanged();
                    IsDirty = true;
                    _GameGlobalDef.FireChanged();
                }
            }
        }
        
        [IgnoreDataMember]
        public int Height
        {
            get { return _Height; }
            set
            {
                if (_Height != value)
                {
                    _Height = value;
                    FireSizeChanged();
                    IsDirty = true;
                    _GameGlobalDef.FireChanged();
                }
            }
        }
        
        [Browsable(false), IgnoreDataMember]
        public GameGlobalDef GlobalDef
        {
            get { return _GameGlobalDef; }
        }

        [Browsable(false), IgnoreDataMember]
        public GamePlayerDefs GamePlayerDefs
        {
            get { return _GamePlayerDefs; }
        }

        [Browsable(false), IgnoreDataMember]
        public GameElementDefs GameElementDefs
        {
            get { return _GameElementDefs; }
        }

        [Browsable(false)]
        public string Xml 
        {
            get { return SpaceSerializer.toString(this); }
        }
        
        [IgnoreDataMember]
        public GameTaskDefs GameTaskDefs
        {
            get { return _GameTaskDefs; }
        }

        [DataMember]
        public string Name
        {
            get { return _Name; }
            set 
            { 
                _Name = value; 
                NotifyPropertyChanged();
            }
        }
        
        [Browsable(false), IgnoreDataMember]
        public bool IsDirty
        {
            get { return _IsDirty; }
            set 
            { 
                if (_IsDirty != value) 
                {
                    _IsDirty = value; 
                    FireDirtyFlagChanged();
                }
            }
        }
        
        private void FireSizeChanged()
        {
            if (SizeChangedEvent != null)
            {
                SizeChangedEvent(this);
            }
        }

        private void NotifyPropertyChanged()
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(""));
            }
        }
    
    }
}
